package com.yunao.web.controller;

import com.alibaba.fastjson.JSONObject;
import com.yunao.commons.Exception.YunaoException;
import com.yunao.commons.constant.CookieConstant;
import com.yunao.commons.constant.RedisConstant;
import com.yunao.commons.enums.ResultEnum;
import com.yunao.commons.serachcore.core.bean.*;
import com.yunao.commons.serachcore.core.help.GroupField;
import com.yunao.commons.serachcore.core.help.SearchFiled;
import com.yunao.commons.utils.CookieUtil;
import com.yunao.commons.utils.DomainSourceUtils;
import com.yunao.commons.utils.JsonUtil;
import com.yunao.commons.utils.ResultVOUtil;
import com.yunao.commons.vo.ResultVO;
import com.yunao.entity.AloneReport;
import com.yunao.entity.ArticleItem;
import com.yunao.entity.Report;
import com.yunao.entity.User;
import com.yunao.service.AlonereportService;
import com.yunao.service.ArticleService;
import com.yunao.service.ReportService;
import com.yunao.service.UserService;
import com.yunao.service.report.Convert;
import com.yunao.service.report.esou.ItextUtil;
import com.yunao.web.annotation.UserLoginToken;
import com.yunao.web.utils.DocBean;
import com.yunao.web.utils.ImReportUtil;
import com.yunao.web.utils.TokenUtil;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.apache.commons.lang3.StringUtils;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.RingPlot;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.chart.title.LegendTitle;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.ui.RectangleEdge;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;
import sun.misc.BASE64Encoder;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.io.*;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.List;

/**
 * 报告
 *
 * @author wuyc
 *
 */
@RestController
@Scope("prototype")
@RequestMapping("/search/report")
public class ReportAction {

    @Autowired
    private ReportService reportService;
    @Autowired
    private AlonereportService aloneReportService;

    private SimpleDateFormat simpleFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * showdoc
     * @catalog API文档/报告模块
     * @title 获取系统生成的报告列表
     * @description 获取专题下全部报告
     * @method post
     * @url /report/report/all
     * @param page 可选 int 页数，默认为1
     * @param pagesize 可选 int 每页条数，默认为20
     * @param aid 必选 int 报告专题ID
     * @return {code: 0,msg: "成功",data: {}}
     * @remark
     * @number 02
     *
     */
    @UserLoginToken
    @RequestMapping("/all")
    public ResultVO sublistAll(
            HttpServletRequest request,
            @RequestParam(defaultValue = "1") Integer page,
            @RequestParam(defaultValue = "20") Integer pagesize,
            String aid
    ){
        String userId = TokenUtil.getTokenUserId();
        Pageable pageable = PageRequest.of(page-1,pagesize,new Sort(Sort.Direction.ASC,"id"));
        List<Report> reportList = reportService.findAllByAloneReportIdAndUserId(aid, userId, pageable);
        return ResultVOUtil.success(reportList);
    }
    /**
     * showdoc
     * @catalog API文档/报告模块
     * @title 日周月报列表
     * @description 分类型获取专题报告
     * @method post
     * @url /report/report/single
     * @param manner 可选 int 报告类型（日、周、月）,默认为日报
     * @param page 可选 int 页数，默认为1
     * @param pagesize 可选 int 每页条数，默认为20
     * @param aid 必选 int 报告专题ID
     * @return {code: 0,msg: "成功",data: {}}
     * @remark
     * @number 03
     */
    @PostMapping("/single")
    @UserLoginToken
    public ResultVO sublist(
            HttpServletRequest request,
            @RequestParam(defaultValue = "1") Integer manner,
            @RequestParam(defaultValue = "1") Integer page,
            @RequestParam(defaultValue = "20") Integer pagesize,
            Integer aid
    ){
        String userId = TokenUtil.getTokenUserId();
        AloneReport aloneReport = aloneReportService.findById(aid);
        Pageable pageable = PageRequest.of(page-1,pagesize,new Sort(Sort.Direction.DESC,"id"));
        List<Report> reports = null;
        if(manner == 1){
            return subjectResult(reports, Convert.getInt(userId),manner,aid,pageable,aloneReport,pagesize,page);
        }
        if(manner == 2){
            return subjectResult(reports,Convert.getInt(userId),manner,aid,pageable,aloneReport,pagesize,page);
        }
        if(manner == 4){
            return subjectResult(reports,Convert.getInt(userId),manner,aid,pageable,aloneReport,pagesize,page);
        }
        return ResultVOUtil.error(ResultEnum.PARAM_ERROR);
    }

    /**
     *
     * showdoc
     * @catalog API文档/报告模块
     * @title 删除自动报告
     * @description 删除选定的自动报告
     * @method get
     * @url /report/report/delete
     * @param id 必选 int 报告专题ID
     * @return {code: 0,msg: "成功",data: ""}
     * @remark
     * @number 04
     */
    @UserLoginToken
    @RequestMapping("/delete")
    public ResultVO<String> delete(
            Integer id
    ) {
        reportService.delete(id);
        return ResultVOUtil.success();
    }
    /**
     * showdoc
     * @catalog API文档/报告模块
     * @title 批量删除自动报告
     * @description 一次性删除多个选定的报告
     * @method post
     * @url /report/report/deleteAll
     * @param ids 必选 string 多个报告ID字符串
     * @return {code: 0,msg: "成功",data: ""}
     * @remark
     * @number 05
     */
    @UserLoginToken
    @RequestMapping(value = "/deleteAll" ,method = {RequestMethod.POST})
    public ResultVO<String> deleteSubs(
            String ids
    ) {
        String[] idsArr = ids.split(",");
        for (int i=0;i<idsArr.length;i++){
            reportService.delete(Integer.parseInt(idsArr[i]));
        }

        return ResultVOUtil.success();
    }
    /**
     * showdoc
     * @catalog API文档/报告模块
     * @title 浏览报告
     * @description 在线浏览自动报告
     * @method post
     * @url /report/report/read
     * @param id 必选 int 报告ID
     * @return {code: 0,msg: "成功",data: {}}
     * @remark
     * @number 06
     */
    @UserLoginToken
    @RequestMapping("/read")
    public ResultVO<String> read(
            Integer id
    ) {
        Report report = reportService.get(id);
        String text = report.getText();
        return ResultVOUtil.success(text);
    }
    /**
     * showdoc
     * @catalog API文档/报告模块
     * @title 下载报告
     * @description 点击下载自动报告
     * @method get
     * @url /search/report/download
     * @param id 必选 int 报告ID
     * @return
     * @remark
     * @number 07
     */
    @UserLoginToken
    @RequestMapping("/download")
    public String report(
            Integer id,
            HttpServletRequest request,
            HttpServletResponse response
    ) throws Exception {
        Report report = reportService.get(id);
        if (report == null)
            throw new YunaoException(ResultEnum.REPORT_EMPTY);
        String filePath = report.getFilePath();
        File reportFile = new File(filePath);
        if (!reportFile.exists())
            throw new Exception("自动报告文件丢失");
        String fileName = report.getName() + ".doc";
        // 用户浏览器
        String userAgent = request.getHeader("USER-AGENT");
        // 解决文件名称乱码问题
        if (StringUtils.contains(userAgent, "MSIE")) {// IE浏览器
            fileName = URLEncoder.encode(fileName, "UTF8");
        } else if (StringUtils.contains(userAgent, "Mozilla")) {// google, 火狐浏览器
            fileName = new String(fileName.getBytes(), "ISO8859-1");
        } else {
            fileName = URLEncoder.encode(fileName, "UTF8");// 其他浏览器
        }
        response.setHeader("Content-disposition", "attachment; filename=" + fileName);
        BufferedOutputStream bufo = null;
        try {
            InputStream in = new FileInputStream(reportFile);
            bufo = new BufferedOutputStream(response.getOutputStream());
            int read = 0;
            byte[] tempbytes = new byte[1024];
            while ((read = in.read(tempbytes)) != -1) {
                bufo.write(tempbytes, 0, read);
                bufo.flush();
            }
        } catch (Exception e) {

        } finally {
            try {
                if (bufo != null)
                    bufo.close();
            } catch (Exception e) {

            }
        }
        return null;
    }

    /**
     * showdoc
     * @catalog API文档/报告模块
     * @title 即时报告
     * @description 根据选取内容生成即时报告
     * @method get
     * @url /search/report/imReport
     * @param ids 必选 int 文章ID
     * @return
     * @remark
     * @number 08
     */
    @UserLoginToken
    @RequestMapping("/imReport")
    public ResultVO imReport(
            String ids,
            HttpServletRequest request,
            HttpServletResponse response
    ){
        //媒体分组数据
        String data=null;
        try {
            Groups mediatypeGroups = reportService.groups(getGroupsMap(ids,null,GroupField.MEDIA_TYPE.toString()));
            if(mediatypeGroups==null){
                return ResultVOUtil.error(ResultEnum.IMREPORT_ERROR);
            }
            //网站分组数据
            Groups hostGroups = reportService.groups(getGroupsMap(ids,null,GroupField.HOST.toString()));
            //情感分组数据
            Groups emotionGroups = reportService.groups(getGroupsMap(ids,null,GroupField.EMOTION.toString()));
            //媒体每日数据
            Cubes mediadayCube = reportService.cube(getCubesMap(ids,null,SearchFiled.GROUPBYDAY.toString(),SearchFiled.MEDIA_TYPE.toString()));
            //作者热度
            Groups authorGroups = reportService.groups(getGroupsMap(ids,null,GroupField.AUTHOR.toString()));
            //正面文章热度
            Clusters posClusters = reportService.cluster(getClustersMap(ids,null,"正面","10","正文","1"));
            //负面文章热度
            Clusters negClusters = reportService.cluster(getClustersMap(ids,null,"负面","10","正文","1"));
            //生成即时报告文件
            File outFile =ImReportUtil.currentImReport(mediatypeGroups, hostGroups, emotionGroups, mediadayCube, authorGroups, posClusters, negClusters);
            //传回文件
            respondeFile(outFile,response,request);

        } catch (Exception e) {

        }
        return null;
    }

    /**
     * 返回日、周、月报列表
     */
    private ResultVO<JSONObject> subjectResult(
            List<Report> reports,
            Integer userid,
            Integer manner,
            Integer aid,
            Pageable pageable,
            AloneReport aloneReport,
            Integer pagesize,
            Integer page
    ){
        reports = reportService.findAllByUserIdAndMannerAndAloneReportId(userid,7,aid,pageable);
        int i = 0;
        if(manner == 1){
            reports.addAll(reportService.findAllByUserIdAndMannerAndAloneReportId(userid,1,aid,pageable));
            reports.addAll(reportService.findAllByUserIdAndMannerAndAloneReportId(userid,3,aid,pageable));
            reports.addAll(reportService.findAllByUserIdAndMannerAndAloneReportId(userid,5,aid,pageable));
            i = Calendar.DAY_OF_YEAR;
        }
        if(manner == 2){
            reports.addAll(reportService.findAllByUserIdAndMannerAndAloneReportId(userid,2,aid,pageable));
            reports.addAll(reportService.findAllByUserIdAndMannerAndAloneReportId(userid,3,aid,pageable));
            reports.addAll(reportService.findAllByUserIdAndMannerAndAloneReportId(userid,6,aid,pageable));
            i  = Calendar.WEEK_OF_YEAR;
        }
        if(manner == 4){
            reports.addAll(reportService.findAllByUserIdAndMannerAndAloneReportId(userid,4,aid,pageable));
            reports.addAll(reportService.findAllByUserIdAndMannerAndAloneReportId(userid,5,aid,pageable));
            reports.addAll(reportService.findAllByUserIdAndMannerAndAloneReportId(userid,6,aid,pageable));
            i  = Calendar.MONTH;
        }
        final int man = i;
        Calendar cal=Calendar.getInstance();
        reports.stream().forEach(
                e -> {
                    Date date = null;
                    try {
                        date = simpleFormatter.parse(e.getCreateDate());
                    } catch (ParseException e1) {
                    }
                    cal.setTime(date);
                    int reportVol = cal.get(man);
                    e.setVol("第"+reportVol+"期");
                }
        );
        JSONObject data = new JSONObject();
        data.put("reports",reports);
        if(aloneReport!=null){
            int totalItems = Integer.parseInt(reportService.countByMannerAndAloneReportIdAndUserId(manner,aid,userid)+"");
            int totalpages = (totalItems%pagesize==0)?(totalItems/pagesize):(totalItems/pagesize+1);
            data.put("totalpages",totalpages);
            data.put("currentpage",page);
            data.put("beginpage",1);
            data.put("endpage",totalpages);
        }
        return ResultVOUtil.success(data);
    }

    private Map getGroupsMap(String ids,String data,String group){
        Map map = new HashMap();
        if (ids!=null) {
            map.put("id",ids);
        }
        if (data!=null) {
            map.put("between",data);
        }
        map.put("group",group);
        return map;
    }
    private Map getCubesMap(String ids,String data,String group1,String group2){
        Map map = new HashMap();
        if (ids!=null) {
            map.put("id",ids);
        }
        if (data!=null) {
            map.put("between",data);
        }
        map.put("group",group1);
        map.put("group2",group2);
        return map;
    }
    private Map getClustersMap(String ids,String data,String emotion,String maxGroup,String mediaType,String distance){
        Map map = new HashMap();
        if (ids!=null) {
            map.put("id",ids);
        }
        if (data!=null) {
            map.put("between",data);
        }
        map.put("emotion",emotion);
        map.put("max_group",maxGroup);
        map.put("media_type",mediaType);
        map.put("distance",distance);
        return map;
    }
    private void respondeFile(File outFile,HttpServletResponse response,HttpServletRequest request) throws Exception{
        if (!outFile.exists())
            throw new Exception("即时报告文件丢失");
        String fileName = System.currentTimeMillis() + ".doc";
        // 用户浏览器
        String userAgent = request.getHeader("USER-AGENT");
        // 解决文件名称乱码问题
        if (StringUtils.contains(userAgent, "MSIE")) {// IE浏览器
            fileName = URLEncoder.encode(fileName, "UTF8");
        } else if (StringUtils.contains(userAgent, "Mozilla")) {// google, 火狐浏览器
            fileName = new String(fileName.getBytes(), "ISO8859-1");
        } else {
            fileName = URLEncoder.encode(fileName, "UTF8");// 其他浏览器
        }
        response.setHeader("Content-disposition", "attachment; filename=" + fileName);
        BufferedOutputStream bufo = null;
        try {
            InputStream in = new FileInputStream(outFile);
            bufo = new BufferedOutputStream(response.getOutputStream());
            int read = 0;
            byte[] tempbytes = new byte[1024];
            while ((read = in.read(tempbytes)) != -1) {
                bufo.write(tempbytes, 0, read);
                bufo.flush();
            }
        } catch (Exception e) {

        } finally {
            try {
                if (bufo != null)
                    bufo.close();
            } catch (Exception e) {

            }
        }
    }
}
